from PyQt4 import QtGui, QtCore
import os, random
from gSystem import mainWindow, TERRAIN_LAYER
from gJson import loadString, loadInteger, loadObject, loadArray, loadCoordinates

GRASS = (1, 39)
FOREST = (15, 39)
OCEAN = (12, 33)

translat = {(1, 39): "Grassland", (15, 39): "Forest", (12, 33): "Ocean"}

class Map(object):
    
    def __init__(self, tiledata = None, cores = None):
        self.tileset = os.path.join("data", "images", "tileset.png")
        
        if tiledata is not None:
            self.tiledat = self.decompressTiles(tiledata)
            self.continentCores = []
            self.decompressCores(cores)
        else:
            self.tiledat = []
            self.continentCores = []
            self.generateTerrain()
            
        self.tiles = [None]*15625
        
        self.createTiles()
    
    def getTileType(self, loc):
        return translat[self.tiledat[loc[0]][loc[1]]]
    
    def generateTerrain(self):
        for x in range(0, 125):
            self.tiledat.append([])
            for y in range(0, 125):
                self.tiledat[x].append(OCEAN)
        for x in range(0, random.randrange(10, 16)):
            self.growContinent((random.randrange(0, 125), random.randrange(0, 125)), 100)
        self.smoothShorelines()
        for x in range(0, random.randrange(40, 80)):
            self.growForest((random.randrange(0, 125), random.randrange(0, 125)), 12000)
        
    def growForest(self, loc, pow):
        if self.tiledat[loc[0]][loc[1]] == OCEAN: return
        self.tiledat[loc[0]][loc[1]] = FOREST
        power = pow - random.randrange(1, 4)
        if power > 0:
            growthlocs = []
            if loc[0] > 0 and self.tiledat[loc[0]-1][loc[1]] == GRASS:
                growthlocs.append((loc[0]-1, loc[1]))
            if loc[1] > 0 and self.tiledat[loc[0]][loc[1]-1] == GRASS:
                growthlocs.append((loc[0], loc[1]-1))
            if loc[0] < 124 and self.tiledat[loc[0]+1][loc[1]] == GRASS:
                growthlocs.append((loc[0]+1, loc[1]))
            if loc[1] < 124 and self.tiledat[loc[0]][loc[1]+1] == GRASS:
                growthlocs.append((loc[0], loc[1]+1))
            if len(growthlocs) == 0: return
            powerr = [power]
            growthpowers = [0]*len(growthlocs)
            while powerr[0] > 0:
                powerr[0] -= 1
                growthpowers[random.randrange(0, len(growthlocs))] += 1
            random.shuffle(growthlocs)
            for i, locc in enumerate(growthlocs):
                self.growForest(locc, growthpowers[i])
    
    def growContinent(self, loc, pow):
        if pow == 100: self.continentCores.append(loc)
        if pow < 35: return
        self.tiledat[loc[0]][loc[1]] = GRASS
        for x in range(-5, 6):
            for y in range(-5, 6):
                if random.randrange(0, 100) < pow:
                    try: self.tiledat[loc[0]+x][loc[1]+y] = GRASS
                    except: pass
        next = (max(0, min(124, loc[0]+random.choice([-6, -4, 4, 6]))), max(0, min(124, loc[1]+random.choice([-6, -4, 4, 6]))))
        self.growContinent(next, pow-random.randrange(3, 7))
        
    def smoothShorelines(self):
        for x in range(1, 124):
            for y in range(1, 124):
                if self.tiledat[x][y] == GRASS and (self.tiledat[x-1][y] == OCEAN or
                                                    self.tiledat[x][y-1] == OCEAN or
                                                    self.tiledat[x+1][y] == OCEAN or
                                                    self.tiledat[x][y+1] == OCEAN):
                    if random.randrange(0, 10) < 3:
                        self.tiledat[x][y] = OCEAN
                elif self.tiledat[x][y] == OCEAN and (self.tiledat[x-1][y] == GRASS or
                                                    self.tiledat[x][y-1] == GRASS or
                                                    self.tiledat[x+1][y] == GRASS or
                                                    self.tiledat[x][y+1] == GRASS):
                    if random.randrange(0, 10) < 3:
                        self.tiledat[x][y] = GRASS
        for x in range(1, 124):
            for y in range(1, 124):
                if self.tiledat[x][y] == GRASS and (self.tiledat[x-1][y] == OCEAN and
                                                    self.tiledat[x][y-1] == OCEAN and
                                                    self.tiledat[x+1][y] == OCEAN and
                                                    self.tiledat[x][y+1] == OCEAN):
                    self.tiledat[x][y] = OCEAN
                if self.tiledat[x][y] == OCEAN and (self.tiledat[x-1][y] == GRASS and
                                                    self.tiledat[x][y-1] == GRASS and
                                                    self.tiledat[x+1][y] == GRASS and
                                                    self.tiledat[x][y+1] == GRASS):
                    self.tiledat[x][y] = GRASS
                
    def createTiles(self):
        mainWindow.glwidget.reserveVBOSize(15625)
        for x in range(0, 125):
            for y in range(0, 125):
                tild = self.tiledat[x][y]
                textureRect = ((tild[0] * 34)+2, (tild[1] * 34)+2, 31, 31)
                drawRect = (x * 32, y * 32, 32, 32)
                temptile = mainWindow.glwidget.createImage(self.tileset, TERRAIN_LAYER, textureRect, drawRect)
                self.tiles[x+y*125] = temptile
                
    def randomCore(self):
        return random.choice(self.continentCores)

    def getFreeAdjacent(self, loc):
        for x in (0, -1, 1):
            for y in (0, -1, 1):
                if y == 0 and x == 0: continue
                if self.tiledat[loc[0]+x][loc[1]+y] != OCEAN:
                    return (loc[0]+x, loc[1]+y)
    
    def compressCores(self):
        result = []
        for item in self.continentCores:
            result += item
        return result
    
    def decompressCores(self, dat):
        for x in range(0, len(dat), 2):
            self.continentCores.append((dat[x], dat[x+1]))
    
    def compressTiles(self):
        result = []
        for list in self.tiledat:
            for coordset in list:
                result += coordset
        return result
    
    def decompressTiles(self, dat):
        result = []
        for x in range(0, 125):
            result.append([])
            for y in range(0, 125):
                result[x].append((dat[x*250+y*2], dat[x*250+y*2+1]))
        return result
    
    def dump(self):
        """Serialize to an object valid for JSON dumping."""

        return dict(tiles=self.compressTiles(), contcores=self.compressCores())
    
    @staticmethod
    def load(obj):
        """Deserialize a new map from a dictionary."""
        map = Map(
            loadCoordinates('Map.tiles', obj.get('tiles')),
            loadCoordinates('Map.contcores', obj.get('contcores')))
        return map
